Pogojni stavek, zanka while ...


Zavarovalnica

1. podnaloga

Zavarovalnica zavarovalno premijo za avtomobilska zavarovanja izračuna takole:

Osnovni znesek je 150 €.

K temu se prišteje znesek, ki je odvisen od prijavljenih zavarovalniških zahtevkov stranke v preteklem letu. Če je bil en zahtevek, se prišteje 30 €; če sta bila dva, se prišteje 50 €; za več kot dva zahtevka pa se prišteje 80 €.

Nadalje se k premiji prišteje fiksna vsota 40 €, če je zavarovanec mladi voznik, tj. če je mlajši od 21 let ali pa ima vozniško dovoljenje manj kot dve leti.

Na koncu se še upošteva, če stranka plačilo poravna z gotovino (5 % popust) ali na obroke (7 % več).

Napišite program, ki glede na podatke o stranki (te preberemo tako, kot kaže zgled) izračuna višino premije (zaokroženo na dve decimalki) in jo izpiše.

Primer:

   Starost voznika: 25
   Koliko let vozniških izkušenj: 5
   Koliko zavarovalnih zahtevkov: 2
   Način plačila (gotovina/na obroke): gotovina
   Premija znaša: 190.0

Uradna rešitev

starost = int(input('Starost voznika: '))
izkusnje = int(input('Koliko let vozniških izkušenj: '))
zahtevki = int(input('Koliko zavarovalnih zahtevkov: '))
placilo = input('Način plačila (gotovina/na obroke): ')


premija = 150 # osnovni znesek

if zahtevki == 1:
    premija += 30
elif zahtevki == 2:
    premija += 50
elif zahtevki > 2:
    premija += 80

if starost < 21 or izkusnje < 2:
    premija += 40

if placilo == "gotovina":
    premija -= 0.05 * premija
else:
    premija += 0.07 * premija
print('Premija znaša:', round(premija,2))

2. podnaloga

Zavarovalni agenti so bili sicer zadovolji s programom, vendar so imeli težave z napačnim vnosom. Zato popravi program tako, da bo:

Primer (tudi tvoj program mora brati podatke v istem vrstnem redu, torej starost, izkušnje, zahtevki, način plačila):

   Starost voznika: 15
   Starost voznika: 25
   Koliko let vozniških izkušenj: 5
   Koliko zavarovalnih zahtevkov: 2
   Način plačila (gotovina/na obroke): kartica
   Način plačila (gotovina/na obroke): pare na sunce
   Način plačila (gotovina/na obroke): gotovina
   Premija znaša: 190.0

To seveda niso edine kotrole, ki bi bile smislene, a ...

Uradna rešitev

starost = 0
while not (18 <= starost <= 100):
    starost = int(input('Starost voznika: '))
izkusnje = int(input('Koliko let vozniških izkušenj: '))
zahtevki = int(input('Koliko zavarovalnih zahtevkov: '))
plačilo = ''
while plačilo != "gotovina" and plačilo != "na obroke":
    plačilo = input('Način plačila (gotovina/na obroke): ')


premija = 150 # osnovni znesek

if zahtevki == 1:
    premija += 30
elif zahtevki == 2:
    premija += 50
elif zahtevki > 2:
    premija += 80

if starost < 21 or izkusnje < 2:
    premija += 40

if plačilo == "gotovina":
    premija -= 0.05 * premija
else:
    premija += 0.07 * premija
print('Premija znaša:', round(premija,2))

Vsote števk

1. podnaloga

Sestavite funkcijo vsota_stevk(n, k), ki vrne vsoto tistih števk celega števila n, ki so večje ali enake k. Kako bi izračunal vsoto vseh števk?

Uradna rešitev

def vsota_stevk(n, k):
    '''Vrne vsoto števk števila n, ki so večje ali enake k'''
    vsota = 0
    n = abs(n) # za primer negativnih števil
    while n > 0:
        stevka = n % 10 # števke gledamo od zadaj (enice)
        if stevka >= k: # ali gre k vsoti 
            vsota += stevka
        n //= 10 # odrežemo že pregledane enice
    return vsota

2. podnaloga

Sestavite funkcijo vsota_stevk_stevil_med(m, n), ki vrne vsoto števk vseh števil med vključno m in n.

Uradna rešitev

def vsota_stevk_stevil_med(m, n):
    '''Vsota števk vseh števil med m in n'''
    vsota = 0
    stevilo = m 
    while stevilo <= n:
        vsota += vsota_stevk(stevilo, 0) # uporabimo funkcijo prejšnje naloge
        stevilo += 1
    return vsota

3. podnaloga

Sestavite funkcijo najmanjse_stevilo_z_vsoto_stevk(n), ki izračuna točno to, kar piše v njenem imenu.

Uradna rešitev

def najmanjse_stevilo_z_vsoto_stevk(n):
    '''Vrne najmanjše število z vsoto števk n'''
    # matematični premislek pove, da se bno število končalo z največ možnimi 9kami
    # spredaj pa, kar še ostane. In če temu prištejemo 1, dobimo zapis števila (ki mu potem odštejemo 1)
    return (n % 9 + 1) * 10 ** (n // 9) - 1
    # 
    # če pa je zadeva videti preveč "zavita", lahko isto idejo udejanimo
    # tudi takole:
    #
    # koliko9 = n // 9 # koliko 9 potrebujemo
    # stev = str(n % 9) + '9' * koliko9
    # return int(stev)

Restavracija

1. podnaloga

V restavraciji morajo nahraniti veliko lačnih ust, zato vsak dan naročijo nekaj hrane. Ker želijo varčevati, obdržijo nekaj hrane iz zaloge, nekaj pa jo naročijo na novo.

Sestavite funkcijo kolikoHrane1(potrebujemo, zaloga), ki vrne količino hrane, ki jo je potrebno dokupiti. V spremenljivki potrebujemo je zapisana količina potrebne hrane, v spremenljivki zaloga pa količina hrane na zalogi. Če hrane ni potrebno dokupiti, naj funkcija vrne število 0. Predpostavite lahko, da sta oba argumenta nenegativni celi števili.

Primer:

>>> kolikoHrane1(15, 5)
10

Uradna rešitev

def kolikoHrane1(potrebujemo, zaloga):
  '''Koliko hrane je potrebno nakupiti'''
  if potrebujemo > zaloga:
    return potrebujemo - zaloga
  else:
    return 0
  # lahko bi napisali tudi brez else,
  # (seveda je return 0 potem ustrezno zamaknjen v levo!
  # saj return pri if tako ali tako zaključi program!
  # lahko pa rešitev skrčimo le v stavek
  #   return max(potrebujemo - zaloga, 0)

2. podnaloga

Zgornja metoda se ni najbolje obnesla, saj ni prav nič upoštevala, kakšno hrano restavracija potrebuje. Zato so hrano razdelili v tri osnovne kategorije. Imenujmo jih hrana tipa 1, tipa 2 in tipa 3.

Sestavite funkcijo kolikoHrane2(potrebujemo1, potrebujemo2, potrebujemo3, zaloga1, zaloga2, zaloga3), ki sprejme šest nenegativnih celih števil. V potrebujemoX je zapisana količina potrebne hrane tipa $X$, v zalogaX pa zaloga hrane tipa $X$.

Funkcija naj vrne tri cela števila (kot return a, b, c - seveda namesto a, b, c uporabimo smiselne spremenljivke). Število na $i$. mestu naj pove, koliko hrane tipa $i$ je treba dokupiti. Če hrane določenega tipa ni potrebno dokupiti, naj na ustrezno mesto zapiše število 0. Če ni potrebno dokupiti nobene hrane, naj funkcija vrne število 0.

Primer:

>>> kolikoHrane2(10,12,7, 12, 8, 5)
0, 4, 2

Uradna rešitev

def kolikoHrane2(potrebujemo1, potrebujemo2, potrebujemo3,
                 zaloga1, zaloga2, zaloga3):
  '''koliko hrane posameznega tipa je potrebno kupiti'''
  potrebnaHranaTip1 = kolikoHrane1(potrebujemo1, zaloga1)
  # brez funkcije kolikoHrane1 bi pač napisali
  # potrebnaHranaTip1 = max(potrebujemo1 - zaloga1, 0)
  potrebnaHranaTip2 = kolikoHrane1(potrebujemo2, zaloga2)
  potrebnaHranaTip3 = kolikoHrane1(potrebujemo3, zaloga3)
  if max(potrebnaHranaTip1, potrebnaHranaTip2, potrebnaHranaTip3) == 0:
      return 0
  return potrebnaHranaTip1, potrebnaHranaTip2, potrebnaHranaTip3

3. podnaloga

Zgornja metoda je požela velik uspeh, a še vedno je najbolj priljubljene hrane včasih zmanjkalo. Zato so se odločili, da bodo najbolj priljubljeno hrane naročili nekaj več, kot bi bilo nujno potrebno.

Sestavite funkcijo kolikoHrane3, ki se obnaša enako kot funkcija kolikoHrane1, le da:

Primer:

>>> kolikoHrane3(15, 5)
20

Uradna rešitev

def kolikoHrane3(potrebujemo, zaloga):
  '''Koliko hrane je potrebno kupiti, če kupimo nekaj na zalogo'''
  if zaloga < potrebujemo/4: 
    return (potrebujemo - zaloga) * 3
  elif zaloga < potrebujemo/2: 
    return (potrebujemo - zaloga) * 2
  elif zaloga < potrebujemo:
    return potrebujemo - zaloga
  else:
    return 0

Ugibaj točke

1. podnaloga

Miha se rad igra igro ugibanja števil. V ta namen bi rad napisal računalniški program, ki bi mu izžrebal število, on pa bi ga ugibal. V pomoč mu sestavite funkcijo relacija(racunalnik, miha), ki sprejme dve celi števili. Funkcija naj vrne niz 'premalo', če je število miha manjše od števila racunalnik; niz 'preveč', če je število miha večje od števila racunalnik in niz 'Bravo!', če sta števili enaki. Primer:

>>> relacija(45, 20)
'premalo'

Uradna rešitev

def relacija(racunalnik, miha):
  '''je miha povedal premalo, preveč ali točno'''
  if racunalnik > miha:
    return 'premalo'
  if racunalnik < miha:
    return 'preveč'
  return 'Bravo!'

2. podnaloga

Mihu je ugibanje v eni dimenziji počasi postalo predolgočasno. Zato je začel ugibati števila, ki ležijo na celoštevilski mreži v ravnini. V ta namen sestavite funkcijo ugibaj(racunalnikX, racunalnikY, mihaX, mihaY), ki sprejme seznama dveh celih števil (točk v ravnini).

Vrne naj niz 'Od prave točke si oddaljen vsaj {0}.', če Miha točke ni uganil in niz 'Bravo!', če je Miha točko uganil. Pri tem naj bo namesto {0} izpisana Evklidska razdalja med točkama miha in racunalnik, zaokrožena navzdol na najbližje celo število.

Primer:

>>> ugibaj(15, 15, 16, 16)
'Od prave točke si oddaljen vsaj 1.'

Uradna rešitev

def ugibaj(racunalnikX, racunalnikY, mihaX, mihaY):
  '''Kako daleč od točke smo'''
  razdalja = int(((racunalnikX - mihaX)**2 + (racunalnikY - mihaY)**2)**0.5)
  if razdalja == 0:
    return 'Bravo!'
  else:
    return 'Od prave točke si oddaljen vsaj ' + str(razdalja) + '.'

3. podnaloga

Miha se je tudi igre v dveh dimenzijah hitro naveličal, saj je trajala predolgo. Zato si je poleg oddaljenosti od izžrebane točke zaželel vedeti še, kje leži njegova točka glede na izžrebano število: v prvem, drugem, tretjem ali četrtem kvadrantu.

Pri tem k prvemu kvadrantu štejemo tudi pozitivno $x$-os, k drugemu pozitivno $y$-os, k tretjemu negativno $x$-os in k četrtemu negativno $y$-os.

Sestavite funkcijo ugibaj1(racunalnikX, racunalnikY, mihaX, mihaY), ki naj vrne niz 'Bravo!', če je Miha točko uganil oz. niz 'Tvoja točka je v {0}. kvadrantu.' (kjer na na namesto {0} izpisana številska oznaka kvadranta).

Primer:

>>> ugibaj1(15, 15, 16, 16)
'Tvoja točka je v 1. kvadrantu.'

>>> ugibaj1(15, 15, 14, 14)
'Tvoja točka je v 3. kvadrantu.'

Uradna rešitev

def ugibaj1(racunalnikX, racunalnikY, mihaX, mihaY):
  '''Ugibanje točke z vrnjenim kvadrantom'''
  razdalja = int(((racunalnikX - mihaX)**2 + (racunalnikY - mihaY)**2)**0.5)
  if razdalja == 0:
      odg = 'Bravo!'
  else:
      kvadrant = 0
      if mihaX > racunalnikX and mihaY >= racunalnikY:
         kvadrant = 1
      elif mihaX >= racunalnikX and mihaY < racunalnikY:
         kvadrant = 4
      elif mihaX <= racunalnikX and mihaY > racunalnikY:
         kvadrant = 2
      elif mihaX < racunalnikX and mihaY <= racunalnikY:
         kvadrant = 3
      odg = 'Tvoja točka je v ' + str(kvadrant) + '. kvadrantu.'
  return odg

Kamion

1. podnaloga

Kamion z nosilnostjo 10 ton porabi 30 litrov dizla na prevoženih 100 km. Naročniku, ki je od skladišča oddaljen d km, je treba pripeljati teza ton peska. Kamion ima trenutno v rezervoarju gorivo litrov dizla.

Ali bo kamion uspešno opravil pot? Če je teža tovora večja od nosilnosti, naj program izpiše

Tovor je pretežak. Kamion ne sme na pot!

Če bo na poti zmanjkalo goriva (nikjer ob poti ni bencinske črpalke), naj program izpiše

Po prevoženih x kilometrih bo zmanjkalo goriva.

kjer je namesto x treba izpisati opravljeno razdaljo, ki naj bo zaokrožena navzdol (na celo število). Sicer naj program izpiše

Kamion bo uspešno dostavil tovor naročniku.

Kako bo kamion prišel nazaj do skladišča, naj vas ne skrbi. Predpostavite še, da teža tovora ne vpliva na porabo goriva. Primer:

     Koliko km: 354
     Koliko je teža peska: 7.5
     Koliko goriva je v rezervoarju: 151.4
     Kamion bo uspešno dostavil tovor naročniku.

Uradna rešitev

d = int(input("Koliko km: "))
teza = float(input("Koliko je teža peska: "))
gorivo = float(input("Koliko goriva je v rezervoarju: "))
x = 100 * gorivo / 30
if teza > 10:
    print('Tovor je pretežak. Kamion ne sme na pot!')
elif x < d:
    print('Po prevoženih', int(x), 'kilometrih bo zmanjkalo goriva.')
else:
    print('Kamion bo uspešno dostavil tovor naročniku.')

Fibonaccijevo zaporedje ostankov

Posplošeno Fibonaccijevo zaporedje ostankov je definirano podobno kot običajno Fibonaccijevo zaporedje , le da si prva dva člena lahko izberemo sami, vse vsote pa računamo po modulu $n$. Vsaj eden od prvih dveh členov mora biti različen od $0$ (po modulu $n$), sicer dobimo zaporedje samih ničel. Vsako takšno zaporedje je periodično (ko se enkrat ponovita prva dva člena, se tudi vsi nadaljnji členi začnejo ponavljati).

V nalogi lahko predpostavite, da velja $n > 1$. Pripravljeno imamo funkcijo funkcijo naslednjiČlen(a, b, n), ki pri podanih zaporednih členih a in b izračuna naslednji člen.

   def naslednjiČlen(a, b, n):
       '''Vrne naslednji člen Fibbonacijevega zaporedja ostankov'''
       return (a + b) % n

1. podnaloga

Če računamo nekaj zaporednih členov za začetna člena 0, 1 in za modul 2, dobimo zaporedje 0, 1, 1, 0, 1, 1, 0, 1, 1 ... Zaporedje ima torej periodo 3. Pri podatkih 0, 1, in 5 pa je zaporedje 0, 1, 1, 2, 3, 0, 3, 3, 1, 4, 0, 4, 4, 3, 2, 0, 2, 2, 4, 1, 0, 1, 1, 2, 3, .. perioda torej kar 20!

Funkcija perioda(a, b, n) kot argumente dobi prva dva člena zaporedja in število n ter naj bi vrnila dolžino periode tega zaporedja. Predpostavite, da velja $a < n$ in $b < n$.

   def perioda(a, b, n):
       '''Dolžina periode FZO z začetnima členoma a in b in operacijo po modulu n
       x = a
       y = naslednjiČlen(a, b, n)
       dopPer = 1
       while x != a and y != b:
           x, y = y, naslednjiČlen(x, y, n)
           dolPer = 1
       return dolPer

Vemo, da so v zgornji kodi štiri napakice in sicer v vrsticah 2, 3, 6 in 8. Popravi jih!

Uradna rešitev

def naslednjiČlen(a, b, n):
    '''Vrne naslednji člen Fibbonacijevega zaporedja ostankov'''
    return (a + b) % n

def perioda(a, b, n):
    '''Dolžina periode FZO z začenima členoma a in b in operacijo po modulu n'''
    x = b
    y = naslednjiČlen(a, b, n)
    dolPer = 1
    while not(x == a and y == b): # dokler se člena ne ponovita - morda je to bolj jasno!
        x, y = y, naslednjiČlen(x, y, n)
        dolPer += 1
    return dolPer

2. podnaloga

Oglej si funkcijo

   def fun1(a, b, n, m):
       '''Vrnem nekaj v povezavi s FZO z začetnima členoma a in b in operacijo po modulu n'''
       x = min(a, b)
       q = a
       w = b
       st = 2
       while st <= m:
           y = naslednjiČlen(q, w, n)
           if y < x:
               x = y
           q = w
           w = y
           st += 1
       return x

S pomočjo te funkcije sestavi funkcijo minMax(a, b, n, m), ki vrne najmanjši in največji člen med prvimi m členi FZO z začetnima členoma a in b, če se operacije izvajajo po modulu n.

       >>>minMax(0, 1, 5, 8)
       (0, 3)
       >>>minMax(1, 1, 5, 4)
       (1, 3)

Namig: Poskušaj razumeti, kaj dana funkcija počne. Spremenljivkam daj smiselna imena. Npr. za y je očitno, da gre za člen v FZ. Tudi q in w imate nekaj zveze s tem. Čemu pa služi x?

Uradna rešitev

def minMax(a, b, n, m):
    '''Vrnem najmanjši in največji člen med prvimi m členi FZO z začetnima členoma a in b in operacijo po modulu n'''
    if m == 1:
        return (a, a)
    najmanj = min(a, b)
    največ = max(a, b)
    predzadnji = a
    zadnji = b
    st = 3
    while st <= m: 
        naslednji = naslednjiČlen(predzadnji, zadnji, n)
        if naslednji < najmanj: # našli smo manjšega
            najmanj = naslednji
        if naslednji > največ: # našli smo večjega
            največ = naslednji
        predzadnji, zadnji = zadnji, naslednji
        st += 1
    return (najmanj, največ)

3. podnaloga

Sestavite funkcijo najkrajšaPerioda(a, b, m, n), ki vrne najmanjši tak $i \in \left[m, n\right]$, pri katerem trojka (a, b, i) minimizira dolžino periode iz prve podnaloge. Predpostavite lahko, da sta argumenta m in n naravni števili in velja $m \leq n$. Primer:

>>> najkrajsa_perioda(2, 2, 6, 19)
8

Namig: Iz 1. podnaloge znamo izračunati dolžino periode. Ta podnaloga pa bi rada samo najkrajšo periodo med vsemi FZO z začetnima členoma a in b, če za modul jemljemo n, n+1, n+2, .., m

Uradna rešitev

def najkrajšaPerioda(a, b, m, n):
    '''Določi pri katerem modulu m <= modul <= n ima FZO najkrajšo periodo'''
    minPer = m # kandidat za modul za najkrajšo periodo
    dolMinPer = perioda(a, b, m) # dolžina te minimalne periode
    modul = m + 1
    while modul <= n: # pregledamo še ostale kandidate
        dolPer = perioda(a, b, modul)
        if dolPer < dolMinPer: # smo našli krajšo?
            minPer = modul
            dolMinPer = dolPer
        modul += 1
    return minPer

Števila: prijateljska, nepopolna ...

1. podnaloga

Sestavite funkcijo vsotaDeliteljev(n), ki bo izračunala vsoto vseh pravih deliteljev števila n. Pravi delitelji so vsi delitelji, razen števila samega, torej tudi 1 (hm, kaj pa za 1? - recimo, da je najbolj logično, da je za 1 vsota pravih deliteljev 0).

>>> vsotaDeliteljev(24)
36

Uradna rešitev

def vsotaDeliteljev(n):
    '''Vrne vsoto pravih deliteljev števila n'''
    delitelj = 1
    vsota = 0
    while delitelj < n:
        if n % delitelj == 0:
            vsota += delitelj
        delitelj += 1
    return vsota
## Lahko pa tudi upoštevamo, da delitelji števila vedno nastopajo v parih.
## def vsotaDeliteljev(n):
##    vsota = 1
##    d = 2
##    while d * d < n: # gremo do korena iz n
##        if n % d == 0:
##            vsota += d
##            vsota += n // d  # še drugi element para
##        d += 1
##    if d * d == n: # če je n slučajno popoln kvadrat
##        vsota += d
##    return vsota

2. podnaloga

Števili a in b sta prijateljski, če je vsota pravih deliteljev števila a enaka številu b, vsota pravih deliteljev števila b pa številu a. Sestavite program, ki premere m in n in izpiše vse takšne pare (a, b) prijateljskih števil, kjer je $m \le a < b \le n$. Primer:

>>>
Spodnja meja: 1000
Zgornja meja: 3000
(1184, 1210)
(2620, 2924)

Pari naj bodo izpisani naraščajoče glede na a. Par izpišemo s print((a, b)).

Uradna rešitev

def vsotaDeliteljev(n):
    '''Vrne vsoto pravih deliteljev števila n'''
    delitelj = 1
    vsota = 0
    while delitelj < n:
        if n % delitelj == 0:
            vsota += delitelj
        delitelj += 1
    return vsota

m = int(input('Spodnja meja: '))
n = int(input('Zgornja meja: '))
a = m
while a <= n: # pregledamo vse možne a-je
    b = vsotaDeliteljev(a)
    vsotaB = vsotaDeliteljev(b)
    # ali je par ustrezen (b je že enak vs.del. a)
    if a < b <= n and a == vsotaB:
            print((a, b))
    a += 1

3. podnaloga

Sestavite funkcijo najblizji_prijateljski_par(m, n), ki poišče in vrne tisti par (a, b) prijateljskih števil, da je $m \le a < b \le n$ in je razlika $b-a$ najmanjša. Če je takšnih parov več, naj vrne prvega med njimi. Če takšnega para ni, naj funkcija vrne par (None, None).

>>> najblizji_prijateljski_par(1000, 3000)
(1184, 1210)

Uradna rešitev

def najblizji_prijateljski_par(m, n):
    '''Najbližji prijateljski števili med m in n'''
    ma = mb = None # z ma in mb bomo označili naj par
    a = m
    while a < n:
        b = vsotaDeliteljev(a)
        if a < b <= n and vsotaDeliteljev(b) == a:
            if ma == None or b - a < mb - ma:
                # če smo našli boljši par (ali sploh prvega)
                ma, mb = a, b
        a += 1
    return ma, mb

4. podnaloga

Sestavite funkcijo nepopolnost(n), ki vrne absolutno razliko med številom n in vsoto vseh njegovih pravih deliteljev.

Uradna rešitev

def nepopolnost(n):
    '''Razlika med številom in vsoto njegovih deliteljev'''
    return abs(n - vsotaDeliteljev(n))

5. podnaloga

Število je popolnoma nepopolno, kadar je njegova nepopolnost večja od njega samega.

Sestavite funkcijo popolnomaNepopolno(n), ki vrne prvo popolnoma nepopolno število, večje ali enako n.

Uradna rešitev

def popolnomaNepopolno(n):
    '''Vrne prvo popolnomaNepopolno število, večje ali enako n'''
    while(nepopolnost(n) <= n):
        n += 1
    return n